package com.linko.intelligent.remote.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.linko.intelligent.remote.core.mapper.DeviceInfoMapper;
import com.linko.intelligent.remote.core.mapper.DeviceOnlineMapper;
import com.linko.intelligent.remote.core.mapper.IotLatLngMapper;
import com.linko.intelligent.remote.core.service.DeviceOnlineTimeCalcService;
import com.linko.intelligent.remote.pojo.po.DeviceInfo;
import com.linko.intelligent.remote.pojo.po.DeviceOnline;
import com.linko.intelligent.remote.pojo.po.IotLatLng;
import com.linko.intelligent.remote.pojo.query.IotQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class DeviceOnlineTimeCalcServiceImpl implements DeviceOnlineTimeCalcService {

    private static final long FIVE_MINUTES_IN_MILLIS = 5 * 60 * 1000;
    @Autowired
    private DeviceInfoMapper deviceInfoMapper;
    @Autowired
    private IotLatLngMapper iotLatLngMapper;
    @Autowired
    private DeviceOnlineMapper deviceOnlineMapper;

    /**
     * 刷新昨天的设备在线时间统计
     */
    public void refreshYesterday() {
        refreshByDate(null);
    }

    /**
     * 刷新今天的设备在线时间统计
     */
    public void refreshToday() {
        refreshByDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
    }

    /**
     * 根据日期列表刷新设备在线时间统计
     *
     * @param dateStrings 日期字符串列表
     */
    public void refreshByDateList(List<String> dateStrings) {
        dateStrings.forEach(this::refreshByDate);
    }

    /**
     * 根据指定日期刷新设备在线时间统计
     *
     * @param day 日期字符串，格式为"yyyy-MM-dd"，null表示昨天
     */
    public void refreshByDate(String day) {
        // 查询所有设备信息
        QueryWrapper deviceQuery = new QueryWrapper();
        List<DeviceInfo> deviceInfos = deviceInfoMapper.selectList(deviceQuery);

        for (DeviceInfo device : deviceInfos) {
            // 获取指定日期的开始时间和结束时间
            Date start = getStartOfDay(day);
            Date end = getEndOfDay(day);

            // 查询设备在指定日期内的位置信息
            IotQuery query = new IotQuery();
            query.setStartTime(start);
            query.setEndTime(end);
            query.setSn(device.getSn());
            List<IotLatLng> latLngList = iotLatLngMapper.selectAll(query);

            // 提取位置信息的上传时间戳并加入当前时间戳作为最后一次在线时间点
            List<Long> timestamps = latLngList.stream()
                    .map(IotLatLng::getUploadTime)
                    .map(Date::toInstant)
                    .map(Instant::toEpochMilli)
                    .collect(Collectors.toList());
            timestamps.add(Instant.now().toEpochMilli());

            // 计算设备总的在线时间
            long totalOnlineTime = calculateTotalOnlineTime(timestamps);

            // 构建设备在线统计对象并插入或更新数据库
            DeviceOnline deviceOnline = new DeviceOnline();
            deviceOnline.setSn(device.getSn());
            deviceOnline.setDate(start);
            deviceOnline.setOnlineDuration(totalOnlineTime / 1000);
            deviceOnline.setOfflineDuration(24 * 3600 - totalOnlineTime / 1000);
            deviceOnline.setStatus(device.getStatus());
            deviceOnline.setIntCreateTime(new Date());

            deviceOnlineMapper.insertOrUpdateDeviceOnline(deviceOnline);
        }
    }

    /**
     * 计算设备总的在线时间
     *
     * @param timestamps 设备在线时间点的时间戳列表
     * @return 总的在线时间（毫秒）
     */
    private long calculateTotalOnlineTime(List<Long> timestamps) {
        long totalOnlineTime = 0;
        int i = 0;
        while (i < timestamps.size() - 1) {
            long currentTime = timestamps.get(i);
            int j = i + 1;
            while (j < timestamps.size() && timestamps.get(j) - currentTime <= FIVE_MINUTES_IN_MILLIS) {
                j++;
            }
            if (timestamps.get(j - 1) - currentTime >= FIVE_MINUTES_IN_MILLIS) {
                totalOnlineTime += timestamps.get(j - 1) - currentTime + 1000;
            } else {
                totalOnlineTime += FIVE_MINUTES_IN_MILLIS;
            }
            i = j;
        }
        return totalOnlineTime;
    }

    /**
     * 获取指定日期的开始时间
     *
     * @param dateStr 日期字符串，格式为"yyyy-MM-dd"，null表示昨天
     * @return 指定日期的开始时间
     */
    private Date getStartOfDay(String dateStr) {
        LocalDate day = (dateStr != null && !dateStr.isEmpty()) ?
                LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")) :
                LocalDate.now().minusDays(1);
        return Date.from(LocalDateTime.of(day, LocalTime.MIN).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取指定日期的结束时间
     *
     * @param dateStr 日期字符串，格式为"yyyy-MM-dd"，null表示昨天
     * @return 指定日期的结束时间
     */
    private Date getEndOfDay(String dateStr) {
        LocalDate day = (dateStr != null && !dateStr.isEmpty()) ?
                LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")) :
                LocalDate.now().minusDays(1);
        return Date.from(LocalDateTime.of(day, LocalTime.MAX).atZone(ZoneId.systemDefault()).toInstant());
    }
}

